ShowTable of Contents
XPages のサーバーサイド JavaScript で Lotus Notes クラスのオブジェクトを扱うときにはオブジェクトのリリースをしてメモリの開放に注意する必要があります。SSJS の処理の裏側では Java の動いており、不要になったオブジェクトは Java のガーベージコレクションで開放されます。しかしLotus Notes クラスのオブジェクトは Java クラスのオブジェクトの中で、Lotus Notes エンジンの C++ コードが呼ばれているため Java のガーベジレコクションの仕組みではオブジェクトの開放ができません。開発者が明示的にC++ コードで生成された Lotus Notes クラスのオブジェクトのの開放を行う必要があります。作成したクラスに対して recycle() メドッドを呼ぶことで、不要になったクラスを解放してSSJS で使用する Lotus Notes クラスを開放します。
この注意事項については、以下の技術文書で説明されています。
Why it is important to use the Recycle() method on every Java object
しかし、この文書の中で「Objects form a hierarchy. For example, recycling a parent document also recycles its children.」とあります。オブジェクトの親子関係によって、親のオブジェクトをリサイクルすれば子オブジェクトもリサイクルされるのですが、この親子関係について分かりにくい部分もあります。たとえば Lotus Notes 文書を参照するためにはアプリケーションからビューを開き、そのビューから文書を開くという操作をおこないます。このときビューのオブジェクトをリサイクルするとどうなるのでしょうか?また文書のオブジェクトをリサイクルしたときに、その文書内のアイテムのオブジェクトはどうなるのでしょう?この記事ではそのようなリサイクルをしたときの適用範囲について解説します。
まずは簡単なデータベースを作成し、XPages の SSJS で Lotus Notes クラスの操作を行ってみましょう。
サンプルのデータベースではフォームに「Subject」フィールドがあり、ノーツ ID でソートされた「ByNoteID」ビューがあるとします。ある XPage の SSJS で以下のようなスクリプトで文書の選択を行い、文書のデータを表示をしたとしましょう。
// 開く文書のノーツ ID
var db = "ABC";
// アプリケーション
var db:NotesDatabase = session.getDatabase("nd853lab/LotusLab","SimpDisc4Recycle.nsf");
print("db.getTitle() = " + db.getTitle());
// ビュー
var v:NotesView = db.getView("ByNoteID");
print("v.getName() = " + v.getName());
// ビュー内の文書エントリ
var entry:NotesViewEntry = v.getEntryByKey(noteID);
print("entry.getNoteID() = " + entry.getNoteID());
// 文書エントリから文書を取得
var doc1:NotesDocument = entry.getDocument();
print("doc1.getNoteID() = " + doc1.getNoteID());
// ビューから文書を取得
var doc2:NotesDocument = v.getDocumentByKey(noteID);
print("doc2.getNoteID() = " + doc2.getNoteID());
// 文書内のアイテム
var item:NotesItem = doc2.getFirstItem("Subject");
print("item.getValueString() = " + item.getValueString());
ここでは以下のような Lotus Notes クラスが生成されています。
-
db Lotus ・・・ Notes アプリケーションを示す NotesDatabase のインスタンス
-
v ・・・ アプリケーション内の「ByNoteID」ビューを示す NotesView のインスタンス
-
doc1, doc2 ・・・ノーツ ID で参照された Lotus Notes 文書を示す NotesDocument のインスタンス
-
Items ・・・ Lotus Notes 文書内の「Subject」アイテムを示す NotesItem クラス。
上のスクリプトでの各オブジェクトの参照経路は以下になります。
ここでで定義された Lotus Notes オブジェクトで recycle() メソッドを呼んでリサイクルすると、そこから生成されたオブジェクトがどのようになるかを見てみましょう。たとえばビューのオブジェクトを以下のようにリサイクルします。
このあとでこれらのオブジェクトのメソッドを以下のように呼び出すスクリプトを追加します。
ここで各オブジェクトのメソッド呼び出しでエラーが発生することを想定し try { } で囲っています。エラーのときは catch(e) の pprint() が表示されます。
try {
print("db.getTitle() = " + db.getTitle());
} catch(e) {
print("db ERROR: " + e.toString());
}
try {
print("v.getName() = " + v.getName());
} catch(e) {
print("v ERROR: " + e.toString());
}
try {
print("entry.getNoteID() = " + entry.getNoteID());
} catch(e) {
print("entry ERROR: " + e.toString());
}
try {
print("doc1.getNoteID() = " + doc1.getNoteID());
} catch(e) {
print("doc1 ERROR: " + e.toString());
}
try {
print("doc2.getNoteID() = " + doc2.getNoteID());
} catch(e) {
print("doc2 ERROR: " + e.toString());
}
try {
print("item.getValueString() = " + item.getValueString());
} catch(e) {
print("item ERROR: " + e.toString());
}
もしオブジェクトがリサイクルされていれば、そのオブジェクトに対するメソッドの呼び出しはエラーになります。たとえば v.recycle() を呼び出したあとでは v.getName() はエラーになります。その結果をまとめたものが以下の表になります。
|
db.recycle() |
v.recycle() |
doc2.recycle |
db:NotesDatabase |
Recycled *1 |
alive |
alive |
v:NotesView |
recycled |
recycled |
alive |
entry:NotesViewEntry |
recycled |
recycled |
alive |
doc1:NotesDocument |
recycled |
alive |
alive |
doc2:NotesDocument |
recycled |
alive |
recycled |
item:NotesItem |
recycled |
alive |
recycled |
*1 NotesDatabase クラスのオブジェクトを session.getCurrentDatabase() で取得していた場合などは、Lotus Notes アプリケーション(データベース)が開かれたままなのでリサイクルは実際に行われない。
はじめに書いたように Lotus Notes クラスのオブジェクトで recycle() メソッドを呼んでリサイクルすると、そのオブジェクトの子オブジェクトもリサイクルされます。しかしここでの子オブジェクトとは、元のオブジェクトから取得できるオブジェクトという意味ではありません。Lotus Notes アプリケーションのデータ構造として親子関係があるかどうかが問題になります。
たとえば Lotus Notes アプリケーション(データベース)はビューや文書などすべての設計要素とデータを含んでいます。そのためビューや文書などはデータベースの子オブジェクトとなり、NotesDatabase クラスのオブジェクトのリサイクルとともにそれらのオブジェクトもリサイクルされます。同じように文書とその中のアイテム(フィールドの値)にも親子関係があり、ビューとビューに表示されるエントリにも親子関係があります。
しかし Lotus Notes アプリケーション内でビューと文書には直接の関係はありません。文書は特定のビューに紐つけられているわけではないからです。そのため NotesView クラスのオブジェクトから getDocumentByKey() メソッドで直接的に、あるいは NotesViewEntry.getDocument() で間接的に取得された NotesDocument クラスのオブジェクトは、元のビューオブジェクトがリサイクルされても生き残ることになります。